#ifndef SERVER_H
#define SERVER_H

#include "msg_node.h"
#include "my_global.h"

#include <cstdint>
#include <utility>
#include <memory>
#include <string.h>
#include <mutex>
#include <string>
#include <queue>
#include <map>

#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>

using TCP = boost::asio::ip::tcp;

class Server;

class Session: public std::enable_shared_from_this<Session>
{
public:
    Session(boost::asio::io_context& ioc, Server* server)
    :m_socket(ioc)
    ,m_server(server)
    ,m_read_buf(new char[MSG_MAX_LENGTH])
    ,m_recv_head_node(new HeadNode(HEAD_LENGTH, 0))
    ,m_head_parse(false)
    {
        m_uuid = boost::uuids::to_string(boost::uuids::random_generator()());
    }

    void Start();
    void Send(const char* msg, size_t len, uint32_t msg_id);
    TCP::socket& GetSocket() { return m_socket;}
    const std::string& GetUuid() const { return m_uuid; }
private:

    void _HadnleRead(const boost::system::error_code& ec, size_t len, std::shared_ptr<Session> self_ptr);
    void _HandleWrite(const boost::system::error_code& ec, std::shared_ptr<Session> self_ptr);
    
private:
    TCP::socket m_socket;   //客户端socket
    Server*     m_server;   //server
    std::string m_uuid;     //唯一标示
    std::unique_ptr<char[]> m_read_buf; //读缓冲区
    std::mutex  m_send_lock;
    std::queue<std::shared_ptr<SendNode>> m_send_que; //发送队列
    
    std::shared_ptr<RecvNode> m_recv_msg_node;   //消息体缓冲区
    std::shared_ptr<HeadNode> m_recv_head_node;   //消息头缓冲区
    bool m_head_parse;     //消息头是否解析完成
};

class Server
{
public:

    Server(boost::asio::io_context&ioc, uint16_t port);
    void DeleteSession(const std::string& uuid);
private:    

    //使用智能指针解决程序崩溃问题
    void _StartAccetp();
    void _HandleAccept(std::shared_ptr<Session> session, const boost::system::error_code& ec);
private:
    boost::asio::io_context& m_ioc; //io上下文 不可以拷贝，只能引用
    TCP::acceptor m_acceptor;       //监听客户端的连接

    std::map<std::string, std::shared_ptr<Session>> m_sessions; 
    std::mutex m_mutex;
};


class LogicNode
{
    friend class Logic;
public:
    LogicNode(std::shared_ptr<Session> session, std::shared_ptr<RecvNode> recv_node)
    :m_session(session)
    ,m_recv_node(recv_node)
    {}
    
private:
    std::shared_ptr<Session> m_session;
    std::shared_ptr<RecvNode> m_recv_node;
};

#endif // SERVER_H